﻿/* Copyright 2007-2008 dnAnalytics Project.
 *
 * Contributors to this file:
 * Patrick van der Velde
 * Marcus Cuda - http://marcus.cuda.net
 *
 * This file is part of dnAnalytics.  dnAnalytics is licensed under the 
 * Microsoft Public License. See License.txt for a complete copy of the
 * license.
 */

namespace dnAnalytics.Math
{
    ///<summary>Provides trigonometric, logarithmic, and other common mathematical functions for complex numbers.</summary>
    public static partial class ComplexMath
    {
        /// <summary>Returns the cosine of a complex number.</summary>
        /// <returns>The cosine of a complex number.</returns>
        /// <param name="value">The complex number to compute the cosine of.</param>
        public static Complex Cos(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_cos(value);
        }

        /// <summary>Returns the hyperbolic cosine of a complex number.</summary>
        /// <returns>The hyperbolic cosine of the complex number.</returns>
        /// <param name="value">The complex number to compute the hyperbolic cosine of.</param>
        public static Complex Cosh(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            if (Complex.IsInfinity(value))
            {
                return Complex.Infinity;
            }

            return SafeNativeMethods.z_cosh(value);
        }

        /// <summary>Returns the exponential of a complex number.</summary>
        /// <returns>The exponential of the complex number.</returns>
        /// <param name="value">The complex number to compute the exponential of.</param>
        public static Complex Exp(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }

            if (value.Imaginary == 0)
            {
                double exp = System.Math.Exp(value.Real);
                return new Complex(exp);
            }
            return SafeNativeMethods.z_exp(value);
        }

        /// <returns>The exponentiation of the given base complex number to the given exponent.</returns>
        /// <summary>Computes the exponentiation a complex number.</summary>
        /// <param name="leftSide">The base.</param>
        /// <param name="rightSide">The exponent.</param>
        public static Complex Pow(Complex leftSide, Complex rightSide)
        {
            return SafeNativeMethods.z_pow(leftSide, rightSide);
        }

        /// <summary>Returns the logarithm of a complex number.</summary>
        /// <returns>The logarithm of the complex number.</returns>
        /// <param name="value">The complex number to compute the logarithm of.</param>
        public static Complex Log(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_log(value);
        }


        /// <summary>Returns the sine of a complex number.</summary>
        /// <returns>The sine of the complex number.</returns>
        /// <param name="value">The complex number to compute the sine of.</param>
        public static Complex Sin(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_sin(value);
        }

        /// <summary>Returns the hyperbolic sine of a complex number.</summary>
        /// <returns>The hyperbolic sine of the complex number.</returns>
        /// <param name="value">The complex number to compute the hyperbolic sine of.</param>
        public static Complex Sinh(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            if (value.Imaginary == 0)
            {
                return new Complex(System.Math.Sinh(value.Real));
            }
            if (value.Real == 0)
            {
                return new Complex(0, System.Math.Sin(value.Imaginary));
            }
            return SafeNativeMethods.z_sinh(value);
        }

        /// <summary>Returns the square root of a complex number.</summary>
        /// <returns>The square root of the complex number.</returns>
        /// <param name="value">The complex number to compute the square root of.</param>
        public static Complex Sqrt(Complex value)
        {
            Complex result;
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }

            if (Complex.IsInfinity(value))
            {
                return Complex.Infinity;
            }

            if ((value.Real == 0.0) && (value.Imaginary == 0.0))
            {
                result = Complex.Zero;
            }
            else
            {
                result = SafeNativeMethods.z_sqrt(value);
            }

            return result;
        }

        /// <summary>Returns the tangent of a complex number.</summary>
        /// <returns>The tangent of the complex number.</returns>
        /// <param name="value">The complex number to compute the tangent of.</param>
        public static Complex Tan(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_tan(value);
        }

        /// <summary>Returns the hyperbolic tangent of a complex number.</summary>
        /// <returns>The hyperbolic tangent of the complex number.</returns>
        /// <param name="value">The complex number to compute the hyperbolic tangent of.</param>
        public static Complex Tanh(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }

            return SafeNativeMethods.z_tanh(value);
        }

        /// <summary>Returns the inverse sine of a complex number.</summary>
        /// <returns>The inverse sine of the complex number.</returns>
        /// <param name="value">The complex number to compute the inverse sine of.</param>
        public static Complex Asin(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }

            return SafeNativeMethods.z_asin(value);
        }

        /// <summary>Returns the inverse cosine of a complex number.</summary>
        /// <returns>The inverse cosine of the complex number.</returns>
        /// <param name="value">The complex number to compute the inverse cosine of.</param>
        public static Complex Acos(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_acos(value);
        }

        /// <summary>Returns the inverse tangent of a complex number.</summary>
        /// <returns>The inverse tangent of the complex number.</returns>
        /// <param name="value">The complex number to compute the inverse tangent of.</param>
        public static Complex Atan(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_atan(value);
        }

        /// <summary>Returns the inverse hyperbolic sine of a complex number.</summary>
        /// <returns>The inverse hyperbolic sine of the complex number.</returns>
        /// <param name="value">The complex number to compute the inverse hyperbolic sine of.</param>
        public static Complex Asinh(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_asinh(value);
        }

        /// <summary>Returns the inverse hyperbolic cosine of a complex number.</summary>
        /// <returns>The inverse hyperbolic cosine of the complex number.</returns>
        /// <param name="value">The complex number to compute the hyperbolic cosine of.</param>
        public static Complex Acosh(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_acosh(value);
        }

        /// <summary>Returns the inverse hyperbolic tangent of a complex number.</summary>
        /// <returns>The inverse hyperbolic tangent of the complex number.</returns>
        /// <param name="value">The complex number to compute the hyperbolic tangent of.</param>
        public static Complex Atanh(Complex value)
        {
            if (Complex.IsNaN(value))
            {
                return Complex.NaN;
            }
            return SafeNativeMethods.z_atanh(value);
        }

        /// <summary>Returns the cosine of a Complex32 number.</summary>
        /// <returns>The cosine of a Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the cosine of.</param>
        public static Complex32 Cos(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_cos(value);
        }

        /// <summary>Returns the hyperbolic cosine of a Complex32 number.</summary>
        /// <returns>The hyperbolic cosine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the hyperbolic cosine of.</param>
        public static Complex32 Cosh(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            if (Complex32.IsInfinity(value))
            {
                return Complex32.Infinity;
            }

            return SafeNativeMethods.c_cosh(value);
        }

        /// <summary>Returns the exponential of a Complex32 number.</summary>
        /// <returns>The exponential of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the exponential of.</param>
        public static Complex32 Exp(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }

            if (value.Imaginary == 0)
            {
                return new Complex32((float)System.Math.Exp(value.Real));
            }
            return SafeNativeMethods.c_exp(value);
        }

        /// <returns>The exponentiation of the given base Complex32 number to the given exponent.</returns>
        /// <summary>Computes the exponentiation a Complex32 number.</summary>
        /// <param name="leftSide">The base.</param>
        /// <param name="rightSide">The exponent.</param>
        public static Complex32 Pow(Complex32 leftSide, Complex32 rightSide)
        {
            return SafeNativeMethods.c_pow(leftSide, rightSide);
        }

        /// <summary>Returns the logarithm of a Complex32 number.</summary>
        /// <returns>The logarithm of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the logarithm of.</param>
        public static Complex32 Log(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_log(value);
        }


        /// <summary>Returns the sine of a Complex32 number.</summary>
        /// <returns>The sine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the sine of.</param>
        public static Complex32 Sin(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_sin(value);
        }

        /// <summary>Returns the hyperbolic sine of a Complex32 number.</summary>
        /// <returns>The hyperbolic sine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the hyperbolic sine of.</param>
        public static Complex32 Sinh(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            if (value.Imaginary == 0)
            {
                return new Complex32((float) System.Math.Sinh(value.Real));
            }
            if (value.Real == 0)
            {
                return new Complex32(0, (float) System.Math.Sin(value.Imaginary));
            }
            return SafeNativeMethods.c_sinh(value);
        }

        /// <summary>Returns the square root of a Complex32 number.</summary>
        /// <returns>The square root of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the square root of.</param>
        public static Complex32 Sqrt(Complex32 value)
        {
            Complex32 result;
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }

            if (Complex32.IsInfinity(value))
            {
                return Complex32.Infinity;
            }

            if ((value.Real == 0.0) && (value.Imaginary == 0.0))
            {
                result = Complex32.Zero;
            }
            else
            {
                result = SafeNativeMethods.c_sqrt(value);
            }

            return result;
        }

        /// <summary>Returns the tangent of a Complex32 number.</summary>
        /// <returns>The tangent of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the tangent of.</param>
        public static Complex32 Tan(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_tan(value);
        }

        /// <summary>Returns the hyperbolic tangent of a Complex32 number.</summary>
        /// <returns>The hyperbolic tangent of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the hyperbolic tangent of.</param>
        public static Complex32 Tanh(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }

            return SafeNativeMethods.c_tanh(value);
        }

        /// <summary>Returns the inverse sine of a Complex32 number.</summary>
        /// <returns>The inverse sine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the inverse sine of.</param>
        public static Complex32 Asin(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }

            return SafeNativeMethods.c_asin(value);
        }

        /// <summary>Returns the inverse cosine of a Complex32 number.</summary>
        /// <returns>The inverse cosine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the inverse cosine of.</param>
        public static Complex32 Acos(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_acos(value);
        }

        /// <summary>Returns the inverse tangent of a Complex32 number.</summary>
        /// <returns>The inverse tangent of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the inverse tangent of.</param>
        public static Complex32 Atan(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_atan(value);
        }

        /// <summary>Returns the inverse hyperbolic sine of a Complex32 number.</summary>
        /// <returns>The inverse hyperbolic sine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the inverse hyperbolic sine of.</param>
        public static Complex32 Asinh(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_asinh(value);
        }

        /// <summary>Returns the inverse hyperbolic cosine of a Complex32 number.</summary>
        /// <returns>The inverse hyperbolic cosine of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the hyperbolic cosine of.</param>
        public static Complex32 Acosh(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_acosh(value);
        }

        /// <summary>Returns the inverse hyperbolic tangent of a Complex32 number.</summary>
        /// <returns>The inverse hyperbolic tangent of the Complex32 number.</returns>
        /// <param name="value">The Complex32 number to compute the hyperbolic tangent of.</param>
        public static Complex32 Atanh(Complex32 value)
        {
            if (Complex32.IsNaN(value))
            {
                return Complex32.NaN;
            }
            return SafeNativeMethods.c_atanh(value);
        }
    }
}